#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <memory>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <cstdlib>
#include "Log.hpp"
using namespace std;

// request请求反序列化
// 业务处理获得响应response
// response响应序列化
static const string sep = "\r\n";
static const string webroot = "wwwroot";
static const string homepage = "index.html";
static const string header_sep = ": ";

static const string version="HTTP/1.0";
static const string space=" ";

static const string filesuffixsep=".";

class Request
{
private:
    string GetOneLine(string &req)
    {
        if (req.empty())
            return string();
        size_t pos = req.find(sep);
        if (pos == string::npos)
            return string();
        string line = req.substr(0, pos);
        req.erase(0, pos + sep.size());
        if (line.empty())
            return sep;
        return line;
    }

    bool ParseReqHeaderHelper(string &header, string *key, string *value)
    {
        if (header.empty())
            return false;
        size_t pos = header.find(header_sep);
        if (pos == string::npos)
            return false;
        *key = header.substr(0, pos);
        *value = header.substr(pos + header_sep.size());
        return true;
    }

public:
    Request()
        : _blank_line(sep), _path(webroot)
    {
    }

    bool ParseReqLine()
    {
        if (_req_line.empty())
            return false;
        stringstream ss(_req_line);
        ss >> _req_method >> _url >> _req_version;
        _path += _url;
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        //解析客户端请求的资源后缀
        size_t pos=_path.rfind(filesuffixsep);
        if(pos==string::npos)
        {
            _suffix=".html";
        }
        else
        {
            _suffix=_path.substr(pos);
        }

        LOG(DEBUG,"client want get %s",_path.c_str());
        return true;
    }

    void ParseReqHeader()
    {
        for (auto &header : _req_header)
        {
            string key, value;
            if (ParseReqHeaderHelper(header, &key, &value))
            {
                _req_headers.insert(make_pair(key, value));
            }
        }
    }

    void Deserialize(string &reqstr)
    {
        _req_line = GetOneLine(reqstr);
        while (true)
        {
            string line = GetOneLine(reqstr);
            if (line == string())
            {
                break;
            }
            else if (line == sep)
            {
                _req_text = reqstr;
                break;
            }
            else
            {
                _req_header.push_back(line);
            }
        }

        // 二次解析请求行
        ParseReqLine();
        // 二次解析请求报头
        ParseReqHeader();
    }

    string Path()
    {
        return _path;
    }

    string Suffix()
    {
        return _suffix;
    }

    ~Request()
    {
    }

private:
    // 按照期望解析结果二次解析
    string _req_method;
    string _url;
    string _path;
    string _suffix;
    string _req_version;
    unordered_map<string, string> _req_headers;

    // 按照原始协议内容初次解析
    string _req_line;           // 请求行
    vector<string> _req_header; // 请求报头
    string _blank_line;         // 空行
    string _req_text;           // 请求正文
};

class Response
{
public:
    Response()
    :_blank_line(sep),_http_version(version)
    {
    }

    //添加状态行
    void AddStatusLine(int code)
    {
        _code=code;
        _desc="OK";
    }

    //添加响应报头
    void AddHeader(const string& key,const string& value)
    {
        _headers[key]=value;
    }

    //添加响应正文
    void AddText(const string& text)
    {
        _resp_text=text;
    }

    string Serialize()
    {
        //状态行序列化
        string statusline=_http_version+space+to_string(_code)+space+_desc+sep;
        //响应报头序列化
        for(auto& header:_headers)
        {
            string linestr=header.first+header_sep+header.second+sep;
            _resp_header.push_back(linestr);
        }

        string response=statusline;
        for(auto& header:_resp_header)
        {
            response += header;
        }
        response += _blank_line;
        response += _resp_text;
        return response;
    }


    ~Response()
    {
    }

private:
    string _http_version;
    int _code;
    string _desc;
    unordered_map<string,string> _headers;


    string _resp_line;
    vector<string> _resp_header;
    string _blank_line;
    string _resp_text;
};

class Factory
{
public:
    static shared_ptr<Request> BuildRequest()
    {
        return make_shared<Request>();
    }

    static shared_ptr<Response> BuildResponse()
    {
        return make_shared<Response>();
    }
};

class HttpServer
{
public:
    HttpServer()
    {

    }

    string ReadFileContent(const string& path,int* size)
    {
        ifstream in(path.c_str(),ios::binary|ios::in);
        if(!in.is_open()) return string();

        in.seekg(0,ios::end);
        int filesize=in.tellg();
        in.seekg(0,ios::beg);

        string filecontent;
        filecontent.resize(filesize);
        in.read((char*)filecontent.c_str(),filesize);
        in.close();
        *size=filesize;
        return filecontent;
    }

    string HandlerHttpServer(string request)
    {
        //1.request反序列化
        shared_ptr<Request> req = Factory::BuildRequest();
        req->Deserialize(request);
        string suffix=req->Suffix();
        //2.业务处理(读取指定路径下的文件内容即获取响应正文)
        int filesize;
        string text=ReadFileContent(req->Path(),&filesize);
        //3.构建必要应答字段
        shared_ptr<Response> resp=Factory::BuildResponse();
        //3.1 构建响应行
        resp->AddStatusLine(200);
        //3.2 构建响应报文
        //Content-Length:flilesize
        resp->AddHeader("Content-Length",to_string(filesize));
        resp->AddHeader("Content-Type",_mime_type[suffix]);
        //3.3 构建响应正文
        resp->AddText(text);
        //4.响应序列化
        string response=resp->Serialize();
        return response;     
    }

    ~HttpServer()
    {
    }

private:
    unordered_map<string,string> _mime_type;
};